package utils

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"os"
)

//生成公钥和私钥 参数bits: 指定生成的秘钥的长度
func RsaGenKey(bits int, privatePath, pubulicPath string) error {
	// 1. 生成私钥文件
	privateKey, err := rsa.GenerateKey(rand.Reader, bits)
	if err != nil {
		return err
	}
	// 2,将rsa私钥序列化为ASN.1 PKCS#1 DER编码
	privateKeyStream := x509.MarshalPKCS1PrivateKey(privateKey)
	block := pem.Block{
		Type:  "RSA Private Key",
		Bytes: privateKeyStream,
	}
	// pricate_path := "./private.pem"
	// 3. 创建文件
	privateKeyFile, err := os.Create(privatePath)
	if err != nil {
		return err
	}
	defer privateKeyFile.Close()
	// 4. 使用pem编码, 并将数据写入文件中
	err = pem.Encode(privateKeyFile, &block)
	if err != nil {
		return err
	}

	// 1. 生成公钥文件
	publicKey := privateKey.PublicKey
	publicKeyStream := x509.MarshalPKCS1PublicKey(&publicKey)
	block = pem.Block{
		Type:  "Public Key",
		Bytes: publicKeyStream,
	}
	// public_path := "./public.pem"
	publicKeyFile, err := os.Create(pubulicPath)
	if err != nil {
		return err
	}
	defer publicKeyFile.Close()
	// 2. 编码公钥, 写入文件
	err = pem.Encode(publicKeyFile, &block)
	if err != nil {
		return err
	}
	return nil
}

//加密公钥
func EncryptRSAPublic(src []byte, public_key string) ([]byte, error) {
	block, _ := pem.Decode([]byte(public_key))
	if block == nil {
		return nil, errors.New("public ---key--- error")
	}
	// 解析公钥 其他语言生成的公钥使用ParsePKIXPublicKey解析 然后使用类型断言
	pubkey, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	// 类型断言
	key := pubkey.(*rsa.PublicKey)
	dst, err := rsa.EncryptPKCS1v15(rand.Reader, key, src)
	if err != nil {
		return nil, err
	}
	return dst, nil
}

//解密私钥
func DecryptRSAPrivate(src []byte, private_key string) ([]byte, error) {
	block, _ := pem.Decode([]byte(private_key))
	if block == nil {
		return nil, errors.New("private key error")
	}

	key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	dst, err := rsa.DecryptPKCS1v15(rand.Reader, key, src)
	if err != nil {
		return nil, err
	}
	return dst, nil
}
